#! /usr/bin/env python

'''
    This file is part of Ognom Keeper.

    Ognom Keeper is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Ognom Keeper is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Ognom Keeper.  If not, see <http://www.gnu.org/licenses/>.


    Copyright(C) 2009 Viktor Vestberg
'''

try:
    from state import *
    from lvlEdit import *
except ImportError, err:
    print str("couldn't load module. %s" % (err))
    
def main():
    game = Game()
    game.run()

class Game:
   """This class is very specific to the game and is not a part of the gameengine. It contains
   alot of gamelogic to prevent bugs and such"""
   def __init__(self, fps=75):
      self.stateManager = StateManager() # See module state for this class
      self.wHandler = WindowHandler()    # See module handlers for this class
      self.fps = fps                     # The maximum frames per second
      self.clock = pygame.time.Clock()   # A clock object for keeping track of time
      self.score = 0                     # Amount of score you currently have
      self.levelScore = 0                # Amount of score you gained this level
      self.hiScore = HiScore()           # Hiscore object for saving score to a file
      self.lives = 6                     # Number of extra lives before dead
      self.canResume = False             # If player can resume the game
      self.scoreView = False             # If we currently view the score, just a buggfix
   # Just run this and everything will initialize and then run the game mainloop
   def run(self):
      self.createWindow()       # Creates a pygame window
      self.setLoading()         # Just blits a picture so the user knows it is loading
      self.init()               # Initialize stuff that cant be initialized in each respective state
      self.mainLoop()           # The holy game mainloop
   # Runs the game
   def mainLoop(self):
      while not pygame.event.peek(pygame.QUIT):  # While we dont get a quitevent from pygame:
        self.clock.tick(self.fps)                # Limit the fps
        self.stateManager.currentState.update()  # Update the current state that is running
        self.wHandler.update()                   # Update the windowhandler
        #This is just a neat thing so that we can see the current fps in the windowtitle
        pygame.display.set_caption("Ognom Keeper, v0.11a fps: %s" % (str(int(self.clock.get_fps()))))
   def createWindow(self):
      self.window = self.wHandler.makeWindow(800, 600, "Ognom Keeper",0)
   def setLoading(self):
      self.window.screen.blit(load_image('loading.png')[0], (0,0))
      self.wHandler.update()    # Must update the screen if we have drawn anything upon it
   def mute(self):
      for state in self.stateManager.stateList: 
         try: state.music.mute()
         except AttributeError: pass # Incase any state doesent have a music-module
   def getFPS(self): 
      return int(self.clock.get_fps())
   def getLives(self):
      return self.lives
   def getScore(self):
      return self.score
   def getLevelScore(self):
      return self.levelScore
   # This is a collidefunction, this is what happens when a player collide with the finish
   def finishCollide(self, shape1, shape2, contact_points, num_contact_points, data):
       if self.scoreView is False:
       # No division by zero here, no sir!
           if self.RunGamestate.wallAdder.numWalls is 0: self.RunGamestate.wallAdder.numWalls += 1
       # Amount of score you recieve
           self.levelScore = (10000/(self.RunGamestate.wallAdder.numWalls))
           self.score += self.levelScore

       self.stateManager.setState(self.FinishState) # Change state to finishstate
       self.scoreView = True
       return True      # If the two shapes should collide or not
   # Another collidefunction, this happens when player collide with a badwall and fails
   def failCollide(self, shape1, shape2, contact_points, num_contact_points, data):
       self.RunGamestate.playerFactory.clean()  # Clean upp all players
       self.RunGamestate.menu.setCurrentFolder(self.tryagainfolder) # Change menu folder, this makes the try again button appear
       self.RunGamestate.physics.paused = True # Pause the physics
       return True
   
   def nextLevel(self):
       if not self.RunGamestate.levelLoader.nextLevel(): self.completeGame() # If it is the last level you complete the game
       else:
           self.RunGamestate.camera.center = self.RunGamestate.playerFactory.players[0]
           self.RunGamestate.wallAdder.numWalls = 0  # Just resets the counter that keeps track of how many walls the player have created
           self.stateManager.setState(self.RunGamestate)
           self.scoreView = False
           self.RunGamestate.physics.paused = False
           self.RunGamestate.music.nextTrack()  # Next track in the playlist
       self.RunGamestate.menu.setCurrentFolder(self.playfolder) # Just a buggfix, changes back the folder so the try again button wont show up
   # This runs when the player click on the try again button
   def tryAgain(self):
       if self.lives < 1: # Check if player is dead
           self.canResume = False       # He cant resume his game if he is dead
           self.CompleteState.setGameOverText() # Change the text in the upcomming state to someting more appropriate
           self.CompleteState.setActive()
       self.lives -= 1  # Decrease number of lives left
       
       pos = self.RunGamestate.levelLoader.level.playerStartPos     # get original player position
       self.RunGamestate.playerFactory.makePlayer(pos)              # reset player position
       self.RunGamestate.physics.paused = False                     # run the physics!
       self.RunGamestate.menu.setCurrentFolder(self.playfolder)     # buggfix, no try again button should appear now
       self.RunGamestate.camera.bgRect.center = pos                 # change camera postion to focus on player
       self.RunGamestate.wallAdder.points = []          # Reset wallpoints, just a buggfix
       self.RunGamestate.levelLoader.reloadLevel()
       self.RunGamestate.camera.center = self.RunGamestate.playerFactory.players[0]  # Change focus of camera, the last player died remember?
   def newGame(self):
       self.RunGamestate.levelLoader.loadFolder('campain')      # Load an entire folder of maps
       self.RunGamestate.wallAdder.numWalls = 0                 # reset number of walls the player created
       self.canResume = True
       self.scoreView = False
       self.RunGamestate.physics.paused = False
       self.RunGamestate.camera.center = self.RunGamestate.playerFactory.players[0]
       self.RunGamestate.menu.setCurrentFolder(self.playfolder)
       self.RunGamestate.setActive()
       self.score = 0
       self.lives = 6
   # This runs when you have completed all of the maps
   def completeGame(self):
       self.canResume = False
       self.scoreView = False
       self.CompleteState.setFinishText()
       self.CompleteState.setActive()
   # This runs when the game is resumed
   def resumeGame(self):
       if self.scoreView: self.FinishState.setActive()
       elif self.canResume: self.RunGamestate.setActive()
       else: pass
   # Load score from a file
   def loadScore(self):
       file = open(os.path.join('data', 'hs.li'),'r')
       self.hiScore = pickle.load(file)
       file.close()
   def saveScore(self):
       file = open(os.path.join('data', 'hs.li'),'rb')
       loadScore = pickle.load(file)
       file.close()
       file = open(os.path.join('data', 'hs.li'),'wb')
       loadScore.scores.append((self.score, self.CompleteState.name.string))
       loadScore.scores.sort()
       loadScore.scores.reverse()
       pickle.dump( loadScore, file, 0 )
       file.close()
       self.stateManager.runFallBackState()
   # This method runs when we wanna view the score in the game
   def hiScores(self):
       self.loadScore()
       self.HiScoreState.updateList(self.hiScore.scores)
       self.HiScoreState.setActive()
   # This simply initializes a load of stuff, kind of a necessary evil
   def init(self):
      self.Menustate = MenuState()
      self.RunGamestate = RunGamestate()
      self.FinishState = FinishState()
      self.CompleteState = CompleteState()
      self.HiScoreState = HiScoreState()
      self.HowToPlayState = HowToPlayState()
      self.LvEditState = LvEditState()
      
      # These just divide the code, nothing more
      self.createMenu()
      self.createCollDetect()
      self.createText()
      
      # Add states to the statemanager so we can handle them better
      self.stateManager.addStates([self.Menustate, self.RunGamestate, self.FinishState, self.LvEditState,
                                   self.CompleteState, self.HiScoreState, self.HowToPlayState])
      
      # Just a way to easily keep track of the menu and run it from different states
      self.stateManager.setFallBackState(self.Menustate)
      self.stateManager.setState(self.Menustate) # Run the menustate first
      
   # Read up on the menuhandler on how this works
   def createMenu(self):
      Startgame = self.Menustate.menu.makePart(self.newGame, "New game", (100,70), 52)
      Level1 = self.Menustate.menu.makePart(self.resumeGame, "Resume Game", (200,70), 42)
      levelfolder = [Startgame, Level1]
    
      Fullscreen = self.Menustate.menu.makePart(self.window.toggleFullscreen, "Fullscreen", (100,70), 24)
      MuteSound = self.Menustate.menu.makePart(self.mute, "Mute Sound", (150,70), 24)
      howtoplay = self.Menustate.menu.makePart(self.HowToPlayState.setActive, "How to play", (200,70), 24)
      optionsfolder = [Fullscreen, MuteSound, howtoplay]
    
      Newgame = self.Menustate.menu.makePart(self.Menustate.menu.setCurrentFolder, "Start", (100,70), 42, levelfolder)
      HiScore = self.Menustate.menu.makePart(self.hiScores, "Highscores", (180,70), 42)
      lvledit = self.Menustate.menu.makePart(self.LvEditState.setActive, "Level Editor", (260,70), 42)
      Options = self.Menustate.menu.makePart(self.Menustate.menu.setCurrentFolder, "Options", (340,70), 42, optionsfolder)
      Quit = self.Menustate.menu.makePart(self.Menustate.manager.quit, "Quit", (420,70), 42)
    
      rootfolder = [Newgame, Options, Quit, HiScore, lvledit]
      ReturnRoot = self.Menustate.menu.makePart(self.Menustate.menu.setCurrentFolder, "Return", (300,70), 42, rootfolder)
      optionsfolder.append(ReturnRoot)
      levelfolder.append(ReturnRoot)
      self.Menustate.menu.setCurrentFolder(rootfolder)
      
      toMenu = self.FinishState.menu.makePart(self.stateManager.runFallBackState, 'Go to menu', (500,100), 20)
      nextlevel = self.FinishState.menu.makePart(self.nextLevel, 'Continue', (500,550), 20)
      
      finishFolder = [toMenu, nextlevel]
      self.FinishState.menu.setCurrentFolder(finishFolder)
      
      toMenu2 = self.HiScoreState.menu.makePart(self.stateManager.runFallBackState, 'Go to menu', (500,60), 20)
      self.HiScoreState.menu.setCurrentFolder([toMenu2])
      
      toMenu3 = self.CompleteState.menu.makePart(self.saveScore, 'Go to menu', (500,100), 20)
      self.CompleteState.menu.setCurrentFolder([toMenu3])
      
      self.tryagainfolder = [self.RunGamestate.menu.makePart(self.tryAgain, 'Try Again', (150,250), 42)]
      freecam = self.RunGamestate.menu.makePart(self.RunGamestate.camera.setFreeCamera, 'Freecam', (30,650), 10)
      followcam = self.RunGamestate.menu.makePart(self.RunGamestate.camera.setFollowCamera, 'Followcam', (50,650), 10)
      restart = self.RunGamestate.menu.makePart(self.tryAgain, 'Restart level', (80,650), 10)
      self.playfolder = [freecam, followcam, restart]
      self.RunGamestate.menu.setCurrentFolder(self.playfolder)
      
   def createCollDetect(self):
      self.RunGamestate.physics.addCollisionAction(self.finishCollide, CollisionType_a=3, CollisionType_b=1, data=None)
      self.RunGamestate.physics.addCollisionAction(self.failCollide, CollisionType_a=1, CollisionType_b=4, data=None)
   
   def createText(self):
      self.RunGamestate.text.makeDynamicText(self.getLives, (15,150), 14, [255,0,0])
      self.FinishState.text.makeDynamicText(self.getScore, (300,370), 20, [255,255,0])
      self.FinishState.text.makeDynamicText(self.getLevelScore, (250,370), 20, [255,255,0])
      self.CompleteState.text.makeDynamicText(self.getScore, (250,450), 20, [255,255,0])

if __name__ == '__main__': main()
